package controllers

import (
	"encoding/json"
	"fmt"
	"strconv"
	"gateway-api/tools"

	"github.com/gin-gonic/gin"
	amqp "github.com/rabbitmq/amqp091-go"
	uuid "github.com/satori/go.uuid"
)

/*
 +----------------------------------------------------------------------
 + Title        : RabbitMQController
 + Author       : huwl
 + Version      : 2.0.0
 + Initial-Time : 2020-11-23
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : RabbitMQ控制层
 +----------------------------------------------------------------------
*/
type RabbitMQController struct {
	BaseController
}

/**
 * 普通队列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) SimpleProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "SimpleProducer")
	contents := ctx.DefaultQuery("contents", "")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 生产者
	err = rm.BaseProducer(
		tools.ExchangeDeclareParams{IsExchangeDeclare: false},
		[]tools.QueueDeclareParams{
			{
				IsQueueDeclare: true,
				Queue:          "simple.queue",
				Durable:        true,
			},
		},
		tools.PublishWithCtx{
			RoutingKey: "simple.queue",
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
			},
		})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("普通队列"))
}

/**
 * 工作队列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) WorkProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "WorkProducer")
	contents := ctx.DefaultQuery("contents", "work work work message")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	exchangeName := "work.exchange"
	queueName := "work.queue"
	kind := "fanout"

	// 申请交换机
	err = rm.ExchangeDeclare(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请队列
	err = rm.QueueDeclare([]tools.QueueDeclareParams{
		tools.QueueDeclareParams{
			IsQueueDeclare: true,
			Queue:          queueName,
			Durable:        true,
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	err = rm.ExchangeBindQueue(tools.QueueBindParam{
		QueueName:    queueName,
		ExchangeName: exchangeName,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 发布消息
	for i := 0; i < 10; i++ {
		// 将结构体转换为JSON字符串
		body, _ := json.Marshal(map[string]interface{}{
			"title":    title + "-" + strconv.Itoa(i),
			"contents": contents + "---" + strconv.Itoa(i),
		})
		err = rm.PublishMessage(tools.PublishWithCtx{
			Exchange: exchangeName,
			AmqpPublishing: amqp.Publishing{
				ContentType:  "application/json",
				Body:         body,
				DeliveryMode: 2,
			},
		})
		if err != nil {
			control.BaseError(ctx, control.WithMessage(err.Error()))
			return
		}
	}

	control.BaseSuccess(ctx, control.WithMessage("工作队列"))
}

/**
 * 广播队列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) FanoutProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "FanoutProducer")
	contents := ctx.DefaultQuery("contents", "FanoutProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	exchangeName := "logs-fanout.exchange"

	queue1 := "logs-fanout.queue-01"
	queue2 := "logs-fanout.queue-02"

	err = rm.BaseProducer(
		tools.ExchangeDeclareParams{
			IsExchangeDeclare: true,
			Name:              exchangeName,
			Kind:              "fanout",
			Durable:           true,
		},
		[]tools.QueueDeclareParams{
			{
				IsQueueDeclare: true,
				Queue:          queue1,
				Durable:        true,
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queue1,
					ExchangeName: exchangeName,
				},
			},
			{
				IsQueueDeclare: true,
				Queue:          queue2,
				Durable:        true,
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queue2,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange: exchangeName,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("广播队列"))
}

/**
 * 定向路由类型消息
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) DirectProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "FanoutProducer")
	contents := ctx.DefaultQuery("contents", "FanoutProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	exchangeName := "direct.exchange"

	q1 := "demo-direct.queue-01"
	k1 := "red"

	q2 := "demo-direct.queue-02"
	k2 := "blue"
	// 指定路由: red
	err = rm.BaseProducer(
		tools.ExchangeDeclareParams{
			IsExchangeDeclare: true,
			Name:              exchangeName,
			Kind:              "direct",
			Durable:           true,
		},
		[]tools.QueueDeclareParams{
			{
				IsQueueDeclare: true,
				Queue:          q1,
				Durable:        true,
				QueueBindParam: tools.QueueBindParam{
					QueueName:    q1,
					RoutingKey:   k1,
					ExchangeName: exchangeName,
				},
			},
			{
				IsQueueDeclare: true,
				Queue:          q2,
				Durable:        true,
				QueueBindParam: tools.QueueBindParam{
					QueueName:    q2,
					RoutingKey:   k2,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: k1,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("定向路由类型消息"))
}

/**
 * 主题类型交换机
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) TopicProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "FanoutProducer")
	contents := ctx.DefaultQuery("contents", "FanoutProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	exchangeName := "topic.exchange"
	kind := "topic"
	publishRoutingKey := "china.weather"

	values := []map[string]string{}
	values = append(values, map[string]string{
		"q": "demo-topic.queue-01",
		"k": "japan.news",
	})
	values = append(values, map[string]string{
		"q": "demo-topic.queue-02",
		"k": "china.news",
	})
	values = append(values, map[string]string{
		"q": "demo-topic.queue-03",
		"k": "china.weather",
	})

	queueDeclareParams := []tools.QueueDeclareParams{}
	for _, value := range values {
		queueDeclareParams = append(queueDeclareParams,
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          value["q"],
				Durable:        true,
				QueueBindParam: tools.QueueBindParam{
					QueueName:    value["q"],
					RoutingKey:   value["k"],
					ExchangeName: exchangeName,
				},
			},
		)
	}

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		queueDeclareParams,
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: publishRoutingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("主题类型交换机"))
}

/**
* 惰性队列
*	- 惰性队列会尽可能的将消息存入磁盘中。
*	- 当消费者下线、宕机、维护而关闭导致长时间内不能消费消息会造成消息的堆积问题?
*	  使用惰性队列将消息存储到磁盘从而去除消息堆积
*	- 缺点性能较差
* @param string title ---------------------------------------必传
* @param string contents ------------------------------------必传
* @return Json
* @author huwl
 */
func (control RabbitMQController) LazyProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "FanoutProducer")
	contents := ctx.DefaultQuery("contents", "FanoutProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "lazy.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "lazy.queue"
	routingKey := "demo-routing"
	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				AmqpTable: map[string]interface{}{
					"x-queue-mode": "lazy",
				},
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("惰性队列"))
}

/**
 * 重试案列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) RetryProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "RetryProducer")
	contents := ctx.DefaultQuery("contents", "RetryProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "retry.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "retry.queue"
	routingKey := "demo-routing"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("重试案列"))
}

/**
 * 幂等性案列
 * 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) IdempotentProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "IdempotentProducer")
	contents := ctx.DefaultQuery("contents", "IdempotentProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "idempotent.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "idempotent.queue"
	routingKey := "demo-routing"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				Queue:   queueName,
				Durable: true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("幂等性案列"))
}

/**
 * 死信队列
 *	- 消息无人消费且已过期将进入死信队列。
 *	- 队列达到最大长度（先入队的消息会被发送到死信队列)。
 *	- 从正常的队列接收消息,但是对消息不进行确认,并且不对消息进行重新投递,此时消息就进入死信队列。
 *	- 消费者拒绝消息。
 *	- 提前在web控制台或者在消费者代码端: 创建死信交换机、死信队列、绑定、设置路由。
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) DeadProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "DeadProducer")
	contents := ctx.DefaultQuery("contents", "DeadProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 正常交换机名称
	exchangeName := "use-dead-queue.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "use-dead-queue.queue"
	routingKey := "demo-routing"

	// 死信交换机
	deadExchangeName := "dead.exchange"
	// 死信交换机与死信队列的routingKey
	deadExchangeQueueRoutingKey := "dead-routing"
	// 当正常队列的消息超过3条则先入队的消息会被发送到死信队列
	maxLength := 3
	// 消息过期时间单位毫秒
	expiration := "100000"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				AmqpTable: map[string]interface{}{
					// 死信交换机名称
					"x-dead-letter-exchange": deadExchangeName,
					// 死信交换机与死信队列的routingKey
					"x-dead-letter-routing-key": deadExchangeQueueRoutingKey,
					// 当正常队列的消息超过3条则先入队的消息会被发送到死信队列
					"x-max-length": maxLength,
				},
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
				// 消息过期时间单位毫秒
				Expiration: expiration,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("死信队列实现延迟消息案列"))
}

/**
 * 延迟消息案列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) DelayProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "DeadProducer--"+tools.GetDate())
	contents := ctx.DefaultQuery("contents", "DeadProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "delay.exchange"
	// 种类
	kind := "x-delayed-message"
	// 队列名称
	queueName := "delay.queue"
	// 路由
	routingKey := "delay-routing"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
		AmqpTable: amqp.Table{
			"x-delayed-type": "direct",
		},
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),

				Headers: amqp.Table{
					// 消息从交换机过期时间,毫秒（x-dead-message插件提供）
					"x-delay": "10000",
				},
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("延迟消息案列"))
}

/**
 * 消息过期【队列没有绑定死信队列的情况下，消息过期则将被删除】
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) MessageExpiredProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "MessageExpiredProducer")
	contents := ctx.DefaultQuery("contents", "MessageExpiredProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "expire.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "expire.queue"
	// 路由
	routingKey := "message-expire-routing"
	// 消息过期时间单位毫秒
	msgExpireTime := "10000"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
				// 消息过期时间单位毫秒
				Expiration: msgExpireTime,
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("消息过期"))
}

/**
 * 队列过期
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) QueueExpiredProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "QueueExpiredProducer")
	contents := ctx.DefaultQuery("contents", "QueueExpiredProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "expired-queue.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "expired-queue.queue"
	// 路由
	routingKey := "queue-expired-routing"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				AmqpTable: amqp.Table{
					// 设置队列过期时间，单位毫秒
					"x-message-ttl": 5000,
				},
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("队列过期"))
}

/**
 * 使用备用交换机案列【详见有道笔记的RabbitMQ相关下的交换机篇】
 * 提前在web ui页面添加备用交换机、备用队列
 * 当消息无法通过正常交换机到达正常队列的时候(即不可路由如：路由写错、队列不存在)，消息则会进入备用交换机
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) BackExchangeProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "BackExchangeProducer")
	contents := ctx.DefaultQuery("contents", "BackExchangeProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "use-back-exchange.exchange"
	// 备用交换机
	backexName := "backup.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "use-back-exchange.queue"
	// 绑定路由
	bindRoutingKey := "normal-routing"
	// 发布消息的路由,当路由错误的时候消息就发送到备用交换机中
	// publishRoutingKey := bindRoutingKey
	publishRoutingKey := "normal"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
		AmqpTable: amqp.Table{
			// 设置备用交换机
			"alternate-exchange": backexName,
		},
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   bindRoutingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: publishRoutingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("使用备用交换机案列"))
}

/**
 * 应答模式生产者
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) AckModeProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "AckModeProducer")
	contents := ctx.DefaultQuery("contents", "AckModeProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "ack-mode.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "ack-mode.queue"
	// 路由
	routingKey := "normal-routing"

	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("应答模式生产者"))
}

/**
 * 优先级队列
 *	- 消息具有优先级即优先消费的等级。
 *	- 必须将消息全部发送到队列中才开启消费者去消费
 *	- 消息需要根据优先级在队列排完序才能让消费者进行消费。
 *	- 优先级的范围0-255,一般使用0-10。"x-max-priority": 10
 *	- 需要设置队列和消息的优先级。
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) PriorityProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "PriorityProducer")
	contents := ctx.DefaultQuery("contents", "PriorityProducer Contents")
	// 消息优先级
	priority, _ := strconv.Atoi(ctx.DefaultQuery("priority", "1"))

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "priority.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "priority.queue"
	// 路由
	routingKey := "normal"
	err = rm.BaseProducer(tools.ExchangeDeclareParams{
		IsExchangeDeclare: true,
		Name:              exchangeName,
		Kind:              kind,
		Durable:           true,
	},
		[]tools.QueueDeclareParams{
			tools.QueueDeclareParams{
				IsQueueDeclare: true,
				Queue:          queueName,
				Durable:        true,
				AmqpTable: amqp.Table{
					// 设置队列优先级,官方范围 0 - 255，一般范围0-10
					"x-max-priority": 10,
				},
				// 交换机绑定队列参数
				QueueBindParam: tools.QueueBindParam{
					QueueName:    queueName,
					RoutingKey:   routingKey,
					ExchangeName: exchangeName,
				},
			},
		},
		tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: routingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),

				// 设置消息优先级
				Priority: uint8(priority),
			},
		}, true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("优先级队列"))
}

/**
 * 生产者Return模式，消息发送至队列时，队列返回
 *	- 消息丢失处理机制：生产者Return模式，消息发送至队列时，队列返回。
 *	- 消息投递到了交换机，但是路由到队列失败。
 * 	- 此时会通过PublisherReturn返回路由异常原因，然后返回ACK，告知投递成功。
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) ReturnProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "ReturnProducer")
	contents := ctx.DefaultQuery("contents", "ReturnProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "return.exchange"

	// 种类
	kind := "direct"

	// 队列名称
	queueName := "return.queue"

	// 绑定路由
	bindRoutingKey := "normal-routing"

	// 发布消息的路由
	publishRoutingKey := "normal-routing"

	// 申请交换机
	err = rm.ExchangeDeclare(tools.ExchangeDeclareParams{
		Name:    exchangeName,
		Kind:    kind,
		Durable: true,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请队列
	err = rm.QueueDeclare([]tools.QueueDeclareParams{
		tools.QueueDeclareParams{
			Queue:   queueName,
			Durable: true,
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	err = rm.ExchangeBindQueue(tools.QueueBindParam{
		QueueName:    queueName,
		RoutingKey:   bindRoutingKey,
		ExchangeName: exchangeName,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 我们使用ch.NotifyReturn方法创建了一个通道来接收确认信息。
	returns := rm.Ch.NotifyReturn(make(chan amqp.Return))

	// 发布消息
	err = rm.PublishMessage(tools.PublishWithCtx{
		Exchange:   exchangeName,
		RoutingKey: publishRoutingKey,
		Mandatory:  true,
		AmqpPublishing: amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
			// 设置消息持久化
			// Transient (0 or 1) or Persistent (2)
			DeliveryMode: 2,
			// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
			MessageId: uuid.NewV4().String(),
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 在ch.PublishWithContext方法之后，我们使用 returnsHandler 来等待队列返回信息。
	go rm.ReturnsHandler(returns)

	control.BaseSuccess(ctx, control.WithMessage("生产者Return模式"))
}

/**
 * 消息丢失处理机制：生产者Confirm模式，消息发送至交换机时，交换机返回确认
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) ConfirmProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "ConfirmProducer")
	contents := ctx.DefaultQuery("contents", "ConfirmProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "confirm.exchange"
	// 种类
	kind := "fanout"
	// 队列名称
	queueName := "confirm.queue"
	// 路由
	routingKey := "normal-routing"

	// 申请交换机
	err = rm.ExchangeDeclare(tools.ExchangeDeclareParams{
		Name:    exchangeName,
		Kind:    kind,
		Durable: true,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请队列
	err = rm.QueueDeclare([]tools.QueueDeclareParams{
		tools.QueueDeclareParams{
			Queue:   queueName,
			Durable: true,
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	err = rm.ExchangeBindQueue(tools.QueueBindParam{
		QueueName:    queueName,
		ExchangeName: exchangeName,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 我们要开启confirm模式，才能接收到这条应答。
	// 开启方式是将Channel.Confirm(noWait bool)参数设置为false，表示同意发送者将当前channel信道设置为confirm模式。
	err = rm.Ch.Confirm(false)
	if err != nil {
		fmt.Println("开启confirm模式错误：", err.Error())
		return
	}

	// 我们使用ch.NotifyPublish方法创建了一个通道来接收确认信息。
	confirms := rm.Ch.NotifyPublish(make(chan amqp.Confirmation))

	// 发布消息
	err = rm.PublishMessage(tools.PublishWithCtx{
		Exchange:   exchangeName,
		RoutingKey: routingKey,
		Mandatory:  true,
		AmqpPublishing: amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
			// 设置消息持久化
			// Transient (0 or 1) or Persistent (2)
			DeliveryMode: 2,
			// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
			MessageId: uuid.NewV4().String(),
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 在ch.PublishWithContext方法之后，我们使用confirmHeadler来等待交换机确认信息。
	go rm.ConfirmHandler(confirms)

	control.BaseSuccess(ctx, control.WithMessage("生产者Return模式"))
}

/**
 * 生产者可靠性案列
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) ReliabilityProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "ReliabilityProducer")
	contents := ctx.DefaultQuery("contents", "ReliabilityProducer Contents")

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 消息确认机制(Confirm模式)
	exitCh := make(chan struct{})
	confirmsCh := make(chan *amqp.DeferredConfirmation)
	confirmsDoneCh := make(chan struct{})
	// Note: this is a buffered channel so that indicating OK to
	// publish does not block the confirm handler
	publishOkCh := make(chan struct{}, 1)

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ(true)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机名称
	exchangeName := "reliable.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "reliable.queue"
	// 路由
	routingKey := "normal-routing"

	// 申请交换机
	err = rm.ExchangeDeclare(tools.ExchangeDeclareParams{
		Name:    exchangeName,
		Kind:    kind,
		Durable: true,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请队列
	err = rm.QueueDeclare([]tools.QueueDeclareParams{
		tools.QueueDeclareParams{
			Queue:   queueName,
			Durable: true,
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	err = rm.ExchangeBindQueue(tools.QueueBindParam{
		QueueName:    queueName,
		ExchangeName: exchangeName,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 处理关闭
	rm.SetupCloseHandler(exitCh)

	// 开始处理确认
	rm.StartConfirmHandler(publishOkCh, confirmsCh, confirmsDoneCh, exitCh)

	// 发送可靠性消息
	rm.PublishReliabilityMessage(tools.PublishWithCtx{
		Exchange:   exchangeName,
		RoutingKey: routingKey,
		AmqpPublishing: amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
			// 设置消息持久化
			// Transient (0 or 1) or Persistent (2)
			DeliveryMode: 2,
			// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
			MessageId: uuid.NewV4().String(),
			AppId:     "sequential-producer",
		},
	}, publishOkCh, confirmsCh, confirmsDoneCh, exitCh)

	control.BaseSuccess(ctx, control.WithMessage("生产者可靠性案列"))
}

/**
 * 持久化生产者【交换机持久化 + 队列持久化 + 消息持久】
 *
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) PersistentProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "PriorityProducer")
	contents := ctx.DefaultQuery("contents", "PriorityProducer Contents")

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 将结构体转换为JSON字符串
	body, _ := json.Marshal(map[string]interface{}{
		"title":    title,
		"contents": contents,
	})

	// 交换机名称
	exchangeName := "persistent.exchange"
	// 种类
	kind := "direct"
	// 队列名称
	queueName := "persistent.queue"
	// 绑定队列路由
	bindRoutingKey := "normal"
	// 发布消息路由
	publishRoutingKey := "normal"

	// 申请持久化交换机
	err = rm.ExchangeDeclare(
		tools.ExchangeDeclareParams{
			Name:    exchangeName, // 交换机名称
			Kind:    kind,         // 种类
			Durable: true,         // 持久化
		},
	)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请持久化队列
	err = rm.QueueDeclare([]tools.QueueDeclareParams{
		tools.QueueDeclareParams{
			Queue:   queueName,
			Durable: true,
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	err = rm.ExchangeBindQueue(tools.QueueBindParam{
		QueueName:    queueName,
		RoutingKey:   bindRoutingKey,
		ExchangeName: exchangeName,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 发布消息
	err = rm.PublishMessage(tools.PublishWithCtx{
		Exchange:   exchangeName,
		RoutingKey: publishRoutingKey,
		AmqpPublishing: amqp.Publishing{
			ContentType: "application/json",
			Body:        body,
			// 设置消息持久化
			// Transient (0 or 1) or Persistent (2)
			DeliveryMode: 2,
			// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
			MessageId: uuid.NewV4().String(),
		},
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithMessage("持久化生产者【交换机持久化 + 队列持久化 + 消息持久】"))
}

/**
 * 三叉戟生产者
 *	- 提前在 web ui 管理平台添加备用交换机
 * @param string title ---------------------------------------必传
 * @param string contents ------------------------------------必传
 * @return Json
 * @author huwl
 */
func (control RabbitMQController) TridentProducer(ctx *gin.Context) {
	title := ctx.DefaultQuery("title", "TridentProducer")
	contents := ctx.DefaultQuery("contents", "TridentProducer Contents")
	priority, _ := strconv.Atoi(ctx.DefaultQuery("priority", "1"))
	num, _ := strconv.Atoi(ctx.DefaultQuery("num", "2"))

	// 创建RabbitMQ
	rm, err := tools.NewRabbitMQ()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机名称
	exchangeName := "trident.exchange"

	// 备用交换机名称
	backupExchangeName := "trident-backup.exchange"

	// 死信交换机名称
	deadExchangeName := "trident-dead.exchange"

	// 队列参数
	queues := []map[string]string{
		{
			"name":    "trident-01.queue",
			"routing": "normal-01",
		},
		{
			"name":    "trident-02.queue",
			"routing": "normal-03",
		},
	}

	// 发布消息路由
	publishRoutingKey := "normal-01"

	// 种类
	kind := "topic"

	// 死信交换机与死信队列的routingKey
	deadExchangeQueueRoutingKey := "trident-dead"

	// 当正常队列的消息超过3条则先入队的消息会被发送到死信队列
	maxLength := 3

	// 组装队列参数
	queueDeclareParamsItems := []tools.QueueDeclareParams{}
	for _, queue := range queues {
		queueDeclareParamsItems = append(queueDeclareParamsItems, tools.QueueDeclareParams{
			Queue:   queue["name"],
			Durable: true,
			AmqpTable: amqp.Table{
				// 死信交换机名称
				"x-dead-letter-exchange": deadExchangeName,
				// 死信交换机与死信队列的routingKey
				"x-dead-letter-routing-key": deadExchangeQueueRoutingKey,
				// 当正常队列的消息超过3条则先入队的消息会被发送到死信队列
				"x-max-length": maxLength,
				// 设置队列优先级,官方范围 0 - 255，一般范围0-10
				"x-max-priority": 10,
				// 惰性队列会尽可能的将消息存入磁盘中。
				// 当消费者下线、宕机、维护而关闭导致长时间内不能消费消息会造成消息的堆积问题?
				// 使用惰性队列将消息存储到磁盘从而去除消息堆积
				// 缺点性能较差
				"x-queue-mode": "lazy",
			},
		})
	}

	// 消息过期时间单位毫秒
	expiration := "0"

	// 申请持久化交换机
	err = rm.ExchangeDeclare(
		tools.ExchangeDeclareParams{
			Name:    exchangeName, // 交换机名称
			Kind:    kind,         // 种类
			Durable: true,         // 持久化
			AmqpTable: amqp.Table{
				"alternate-exchange": backupExchangeName,
			},
		},
	)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 申请持久化队列
	err = rm.QueueDeclare(queueDeclareParamsItems)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 交换机绑定队列
	for _, queue := range queues {
		err = rm.ExchangeBindQueue(tools.QueueBindParam{
			QueueName:    queue["name"],
			RoutingKey:   queue["routing"],
			ExchangeName: exchangeName,
		})
		if err != nil {
			control.BaseError(ctx, control.WithMessage(err.Error()))
			return
		}
	}

	// 发布消息
	for i := 1; i < num; i++ {
		// 将结构体转换为JSON字符串
		body, _ := json.Marshal(map[string]interface{}{
			"title":    title + "-" + strconv.Itoa(i),
			"contents": contents + "-" + strconv.Itoa(i),
		})

		// 我们要开启confirm模式，才能接收到这条应答。
		// 开启方式是将Channel.Confirm(noWait bool)参数设置为false，表示同意发送者将当前channel信道设置为confirm模式。
		err = rm.Ch.Confirm(false)
		if err != nil {
			control.BaseError(ctx, control.WithMessage(err.Error()))
			return
		}

		// 我们使用ch.NotifyPublish方法创建了一个通道来接收确认信息。
		confirms := rm.Ch.NotifyPublish(make(chan amqp.Confirmation))

		// 消息丢失处理机制：生产者Return模式，消息发送至队列时，队列返回
		// 消息投递到了交换机，但是路由到队列失败。
		// 此时会通过PublisherReturn返回路由异常原因，然后返回ACK，告知投递成功
		returns := rm.Ch.NotifyReturn(make(chan amqp.Return))

		err = rm.PublishMessage(tools.PublishWithCtx{
			Exchange:   exchangeName,
			RoutingKey: publishRoutingKey,
			AmqpPublishing: amqp.Publishing{
				ContentType: "application/json",
				Body:        body,
				// 设置消息持久化
				// Transient (0 or 1) or Persistent (2)
				DeliveryMode: 2,
				// 设置消息唯一标识消息ID实现消息消费的幂等性即解决重复消费问题
				MessageId: uuid.NewV4().String(),

				// 设置消息优先级
				Priority: uint8(priority),

				// 消息过期时间单位毫秒
				Expiration: expiration,
			},
		})
		if err != nil {
			control.BaseError(ctx, control.WithMessage(err.Error()))
			return
		}

		// 在ch.PublishWithContext方法之后，我们使用confirmHeadler来等待交换机确认信息。
		go rm.ConfirmHandler(confirms)

		// 在ch.PublishWithContext方法之后，我们使用 returnsHandler 来等待队列返回信息。
		go rm.ReturnsHandler(returns)
	}

	control.BaseSuccess(ctx, control.WithMessage("三叉戟队列"))
}
